package org.sixtynine.stock.controller;

import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.sixtynine.stock.Constants.CommonData;
import org.sixtynine.stock.ReturnData;
import org.sixtynine.stock.dto.GridPramDTO;
import org.sixtynine.stock.entity.BaseEntity;
import org.sixtynine.stock.entity.Company;
import org.sixtynine.stock.entity.User;
import org.sixtynine.stock.model.FileUploadForm;
import org.sixtynine.stock.model.LoadingSearchCriteria;
import org.sixtynine.stock.service.GenericService;
import org.sixtynine.stock.service.content.DataManagerService;
import org.sixtynine.stock.service.file.FileDataService;
import org.sixtynine.stock.util.SessionBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

/**
 * super class for price data controlllers
 * 
 * @author Thilanka
 * 
 */
public abstract class PriceDataController extends BackEndAuthController {

	/** TODO configure */
	protected int RECORDS_PER_PAGE = 10;

	@Autowired
	protected GenericService genericService;

	@Autowired
	protected FileDataService fileDataService;

	@Autowired
	DataManagerService dataManagerService;

	protected static final String BIND_VAL_COMPANY_MAP = "companyMap";
	protected static final String BIND_VAL_MESSAGE = "message";
	protected static final String BIND_VAL_FILE_UPLOAD = "uploadFile";
	protected static final String BIND_VAL_CRITERIA = "criteria";

	/**
	 * bind the company map
	 * 
	 * @param modelAndView
	 */
	protected void bindCompanyList(ModelAndView modelAndView) {
		List<BaseEntity> companies = dataManagerService
				.getData(CommonData.COMPANY.toString());
		modelAndView.addObject(BIND_VAL_COMPANY_MAP, companies);
	}

	public ModelAndView search(@ModelAttribute LoadingSearchCriteria criteria,
			HttpServletRequest request) {
		ModelAndView modelAndView = null;
		if (!isUserLogged(request)) {
			modelAndView = new ModelAndView("/login/login");
			modelAndView.addObject("registedUser", new User());
			return modelAndView;
		}
		modelAndView = new ModelAndView(getPage());
		loadData(1, -1, criteria.getCompanyId(), criteria.getCompanyName(),
				criteria.getFromDate(), criteria.getToDate(), modelAndView,
				criteria);
		SessionBean sBean = SessionBean.getInstance(request);
		sBean.setAttr(SEARCH_CRITERIA, criteria);
		return modelAndView;
	}

	protected abstract Class getBaseClass();

	/**
	 * @return should give
	 */
	protected abstract String getPage();

	/**
	 * @return page share data
	 */
	protected abstract void setPageData(int companyId, Date fromDate,
			Date toDate, String sortByFirst, String sortBySecond,
			GridPramDTO gridPramDTO, ModelAndView modelAndView);

	/**
	 * load data
	 * 
	 * @param page
	 * @param totalRecords
	 * @param companyId
	 * @param fromDate
	 * @param toDate
	 * @param modelAndView
	 */
	protected void loadData(Integer page, Integer totalRecords, int companyId,
			String companyName, Date fromDate, Date toDate,
			ModelAndView modelAndView, LoadingSearchCriteria criteria) {
		GridPramDTO gridPramDTO = new GridPramDTO();
		gridPramDTO.setRows(RECORDS_PER_PAGE);
		if (page != null) {
			gridPramDTO.setPage(page);
		} else {
			gridPramDTO.setPage(1);
		}
		if (totalRecords != null) {
			gridPramDTO._setTotalNumberOfRecords(totalRecords);
		}

		// populate the search criteria from the session
		if(criteria!=null) {
			companyId = criteria.getCompanyId();
			companyName = criteria.getCompanyName();
			fromDate = criteria.getFromDate();
			toDate = criteria.getToDate();
		}
		
		List<BaseEntity> compaies = dataManagerService
				.getData(CommonData.COMPANY.toString());
		if (companyId <= 0 && !StringUtils.isEmpty(companyName)) {
			for (BaseEntity baseEntity : compaies) {
				Company company = (Company) baseEntity;
				if (company != null && company.getName().equals(companyName)) {
					companyId = company.getId();
					break;
				}
			}
		}
		// if company id is not set, set it as -1
		if(companyId==0) {
			companyId = -1;
		}

		setPageData(companyId, fromDate, toDate, null, null, gridPramDTO,
				modelAndView);

		modelAndView.addObject(BIND_VAL_COMPANY_MAP, compaies);
		if (criteria == null) {
			criteria = new LoadingSearchCriteria();

			criteria.setCompanyId(companyId);
			criteria.setFromDate(fromDate);
			criteria.setToDate(toDate);
		}
		modelAndView.addObject(BIND_VAL_CRITERIA, criteria);

	}

	/**
	 * delete selected share data list
	 * 
	 * @param deleteIds
	 * @return model view
	 */
	public ModelAndView deleteSelected(Integer[] deleteIds) {
		ModelAndView modelAndView = null;
		if (deleteIds != null) {
			for (Integer deleteId : deleteIds) {
				genericService.delete(deleteId, getBaseClass());
			}
		}

		modelAndView = new ModelAndView(getPage());
		// set the criteria
		modelAndView.addObject(BIND_VAL_CRITERIA, new LoadingSearchCriteria());
		String message = "Selected Records deleted successfully.";
		modelAndView.addObject(BIND_VAL_MESSAGE, message);

		loadData(1, -1, -1, null, null, null, modelAndView, null);
		return modelAndView;
	}

	public ModelAndView deleteShareData(Integer id) {
		ModelAndView modelAndView = new ModelAndView(getPage());
		genericService.delete(id, getBaseClass());

		modelAndView.addObject(BIND_VAL_CRITERIA, new LoadingSearchCriteria());
		String message = "Record successfully deleted.";
		modelAndView.addObject(BIND_VAL_MESSAGE, message);
		loadData(1, -1, -1, null, null, null, modelAndView, null);
		return modelAndView;
	}

	/**
	 * @param shareData
	 * @param result
	 * @return the view of edit page
	 */
	public ModelAndView editShareData(BaseEntity shareData, BindingResult result) {

		ModelAndView modelAndView = null;
		if (!result.hasErrors()) {
			genericService.saveOrUpdate(shareData);
			modelAndView = new ModelAndView(getPage());

			modelAndView.addObject(BIND_VAL_CRITERIA,
					new LoadingSearchCriteria());
			String message = "Record successfully updated.";
			modelAndView.addObject(BIND_VAL_MESSAGE, message);

			loadData(1, -1, shareData, modelAndView, null);
		} else {
			modelAndView = new ModelAndView(getEditPage());

			List<BaseEntity> compaies = dataManagerService
					.getData(CommonData.COMPANY.toString());
			modelAndView.addObject(BIND_VAL_COMPANY_MAP, compaies);

			String message = "Please enter correct data.";
			modelAndView.addObject(BIND_VAL_MESSAGE, message);
		}

		return modelAndView;
	}

	protected abstract String getEditPage();

	protected abstract void loadData(Integer page, Integer totalRecords,
			BaseEntity shareData, ModelAndView modelAndView,
			LoadingSearchCriteria criteria);

	/**
	 * show edit page for a object
	 * 
	 * @param id
	 * @return view
	 */
	protected ModelAndView showEdit(Integer id) {
		ModelAndView modelAndView = new ModelAndView(getEditPage());
		BaseEntity dailyShareData = genericService.findById(id, getBaseClass());
		modelAndView.addObject(getObjBindName(), dailyShareData);
		List<BaseEntity> compaies = dataManagerService
				.getData(CommonData.COMPANY.toString());
		modelAndView.addObject(BIND_VAL_COMPANY_MAP, compaies);

		return modelAndView;
	}

	protected abstract String getObjBindName();

	protected ModelAndView showList(HttpServletRequest request, Integer page,
			Integer totalRecords) {
		SessionBean sBean = SessionBean.getInstance(request);
		LoadingSearchCriteria criteria = (LoadingSearchCriteria) sBean
				.getAttr(SEARCH_CRITERIA);
		ModelAndView modelAndView = new ModelAndView(getPage());
		loadData(page, totalRecords, -1, null, null, null, modelAndView,
				criteria);

		return modelAndView;
	}

	protected abstract String getAddPage();

	/**
	 * @param request
	 * @param uploadFile
	 * @return the view
	 */
	protected ModelAndView addShareByFile(HttpServletRequest request,
			FileUploadForm uploadFile) {

		ModelAndView modelAndView = new ModelAndView(getAddPage());
		bindDummyObject(modelAndView);

		MultipartFile multipartFile = uploadFile.getFile();
		ReturnData<String> fileSaveReturnData = fileDataService.saveFile(
				multipartFile, getExelProcessorType(), null);

		StringBuilder message = new StringBuilder();
		if (fileSaveReturnData._isSuccess()) {
			// if success, process it
			ReturnData<List<? extends BaseEntity>> returnData = fileDataService
					.process(multipartFile.getOriginalFilename(),
							getExelProcessorType());

			if (returnData._isSuccess()) {
				message.append("file " + multipartFile.getOriginalFilename()
						+ " uploaded and inserted successfully");
				modelAndView = new ModelAndView(getPage());
				modelAndView.addObject(BIND_VAL_CRITERIA,
						new LoadingSearchCriteria());
				loadData(1, -1, -1, null, null, null, modelAndView, null);

			} else {
				modelAndView = new ModelAndView(getAddPage());
				bindDummyObject(modelAndView);
				bindCompanyList(modelAndView);
				bindFileUpload(modelAndView);
				message.append(returnData.getMsg());
			}
		} else {
			modelAndView = new ModelAndView(getAddPage());
			bindDummyObject(modelAndView);
			bindCompanyList(modelAndView);
			bindFileUpload(modelAndView);
			message.append(fileSaveReturnData.getMsg());
		}
		modelAndView.addObject(BIND_VAL_MESSAGE, message);

		return modelAndView;
	}

	protected abstract String getExelProcessorType();

	protected abstract String getCompanyExcelProcessorType();

	protected abstract void bindFileUpload(ModelAndView modelAndView);

	protected abstract void bindDummyObject(ModelAndView modelAndView);

	/**
	 * @param uploadFile
	 * @return the view
	 */
	public ModelAndView processShareDataByCompany(FileUploadForm uploadFile) {
		ModelAndView modelAndView = new ModelAndView(getAddPage());

		bindDummyObject(modelAndView);
		MultipartFile multipartFile = uploadFile.getFile();
		ReturnData<String> fileSaveReturnData = fileDataService.saveFile(
				multipartFile, getCompanyExcelProcessorType(), null);

		StringBuilder message = new StringBuilder();
		if (fileSaveReturnData._isSuccess()) {
			// if success, process it
			ReturnData<List<? extends BaseEntity>> returnData = fileDataService
					.process(multipartFile.getOriginalFilename(),
							getCompanyExcelProcessorType());

			if (returnData._isSuccess()) {
				message.append("file " + multipartFile.getOriginalFilename()
						+ " uploaded and inserted successfully");
				modelAndView = new ModelAndView(getPage());
				modelAndView.addObject(BIND_VAL_CRITERIA,
						new LoadingSearchCriteria());
				loadData(1, -1, -1, null, null, null, modelAndView, null);

			} else {
				modelAndView = new ModelAndView(getAddPage());
				bindDummyObject(modelAndView);
				bindCompanyList(modelAndView);
				bindFileUpload(modelAndView);
				message.append(returnData.getMsg());
				modelAndView.addObject(BIND_VAL_MESSAGE, message);
			}
		} else {
			modelAndView = new ModelAndView(getAddPage());

			bindDummyObject(modelAndView);
			bindCompanyList(modelAndView);
			bindFileUpload(modelAndView);
			message.append(fileSaveReturnData.getMsg());
			modelAndView.addObject(BIND_VAL_MESSAGE, message);
		}
		modelAndView.addObject(BIND_VAL_MESSAGE, message);

		return modelAndView;
	}
}
